import os
from bs4 import BeautifulSoup
import markdown
import pdfkit
import time # 导入 time 模块，可能用于增加延迟

def set_pdfkit():
    """配置 wkhtmltopdf 路径"""
    # 确保这个路径在你的系统上是正确的
    try:
        config = pdfkit.configuration(wkhtmltopdf=r"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe")
        # 尝试调用 wkhtmltopdf --version 来验证路径和程序是否可用
        # 注意：直接调用 config.wkhtmltopdf('--version') 可能不会按预期工作
        # 一个更可靠的方法是尝试转换一个简单的字符串
        pdfkit.from_string("test", False, configuration=config)
        print("wkhtmltopdf 配置成功。")
        return config
    except Exception as e:
        print(f"配置 wkhtmltopdf 失败: {e}")
        print("请确保 wkhtmltopdf 已安装，并且路径设置正确。")
        print("可以从 https://wkhtmltopdf.org/downloads.html 下载。")
        # 打印 PATH 环境变量帮助调试
        print(f"当前系统 PATH: {os.environ.get('PATH')}")
        return None # 返回 None 表示配置失败

def process_md_file(md_path, config):
    """处理单个 Markdown 文件，生成 HTML 和 PDF"""
    if not config:
        print(f"wkhtmltopdf 配置无效，跳过文件: {md_path}")
        return # 如果配置失败，则不处理文件

    print(f"正在处理: {md_path}") # 添加日志记录
    dir_path = os.path.dirname(md_path)
    base_name = os.path.splitext(os.path.basename(md_path))[0]
    # 使用稍微不同的名称作为临时 HTML 文件，以避免潜在冲突
    html_file = os.path.join(dir_path, base_name + '_temp.html')
    pdf_file = os.path.join(dir_path, base_name + '.pdf')

    # 读取 Markdown 文件内容
    try:
        with open(md_path, 'r', encoding='utf-8') as f:
            md_text = f.read()
    except Exception as e:
        print(f"读取 Markdown 文件失败 {md_path}: {e}")
        return # 如果读取失败则跳过此文件

    # 使用 Markdown 库转换为 HTML 片段
    # 如果需要更好的 Markdown 支持，可以添加 'extra', 'codehilite' 扩展
    # 可能需要安装： pip install markdown pygments
    try:
        # 使用 'fenced_code' 来支持 ```code``` 语法块
        md = markdown.Markdown(output_format='html5', extensions=['extra', 'codehilite', 'fenced_code'])
        html_content = md.convert(md_text)
        use_codehilite_style = 'codehilite' in md.registeredExtensions
    except Exception as e:
        print(f"Markdown 转换失败 {md_path}: {e}")
        # 如果转换失败，尝试不带扩展的基本转换
        try:
             md = markdown.Markdown(output_format='html5')
             html_content = md.convert(md_text)
             use_codehilite_style = False
        except Exception as e_basic:
             print(f"基本的 Markdown 转换也失败了 {md_path}: {e_basic}")
             return # 如果基本转换也失败，则跳过

    # 使用 BeautifulSoup 提取 h1 并从内容中移除
    try:
        soup = BeautifulSoup(html_content, 'html.parser')
        h1_tag = soup.find('h1')
        if h1_tag:
            title = h1_tag.get_text(strip=True)
            h1_tag.extract() # 从主要内容中移除 h1 标签
            processed_content = str(soup)
        else:
            title = base_name # 使用文件名作为备用标题
            processed_content = str(soup) # 即使没有h1也要转换回字符串
    except Exception as e:
        print(f"BeautifulSoup 处理失败 {md_path}: {e}")
        # 如果 BeautifulSoup 出错，尝试使用原始 html_content
        title = base_name
        processed_content = html_content


    # --- MathJax 配置 ---
    # 使用 MathJax 2 CDN. 确保你的机器可以访问此 URL.
    mathjax_config = """
        <script type="text/x-mathjax-config">
          MathJax.Hub.Config({
            tex2jax: {
              inlineMath: [['$','$'], ['\\\\(','\\\\)']],
              displayMath: [['$$','$$'], ['\\\\[','\\\\]']],
              processEscapes: true
            },
            "HTML-CSS": {
               linebreaks: { automatic: true },
               scale: 100 // 如果需要，调整缩放比例
            },
             SVG: {
               linebreaks: { automatic: true },
               scale: 100 // 如果需要，调整缩放比例
            },
            showProcessingMessages: false, // 可以设为 false 减少控制台输出
            messageStyle: "none" // 可以设为 none 减少控制台输出
          });
        </script>
        <script type="text/javascript"
           src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
        </script>
    """
    # --- 结束 MathJax 配置 ---

    # --- CSS 样式 ---
    css_styles = ""
    common_style = """
        body { font-family: sans-serif; line-height: 1.6; }
        h1 { border-bottom: 1px solid #ccc; padding-bottom: 5px; margin-bottom: 1em;}
        pre { background-color: #f0f0f0; padding: 10px; border-radius: 3px; overflow: auto; white-space: pre-wrap; word-wrap: break-word;}
        code { background-color: #f0f0f0; padding: 2px 4px; border-radius: 3px; font-family: monospace; }
        /* Example for body font size: body {{ font-size: 16px; }} */
    """
    codehilite_style = """
        /* Styling for code blocks generated by codehilite */
        .codehilite pre { background-color: #f0f0f0; padding: 10px; border-radius: 3px; overflow: auto; }
        .codehilite code { background-color: transparent; padding:0; border-radius:0; } /* Reset inline code style within pre */
    """
    if use_codehilite_style:
        css_styles = f"<style>{common_style}{codehilite_style}</style>"
    else:
        css_styles = f"<style>{common_style}</style>"
    # --- 结束 CSS 样式 ---


    # 构建完整的 HTML 文档
    # **移除了之前 f-string 内部的 Python 注释**
    full_html = f'''
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <title>{title}</title>
        {mathjax_config}
        {css_styles}
    </head>
    <body>
        <h1>{title}</h1>
        {processed_content}
    </body>
    </html>
    '''

    # 写入临时 HTML 文件
    try:
        with open(html_file, 'w', encoding='utf-8') as f:
            f.write(full_html)
        print(f"临时 HTML 文件已写入: {html_file}")
    except Exception as e:
        print(f"写入临时 HTML 文件失败 {html_file}: {e}")
        return # 如果无法写入 HTML 则跳过

    # 设置 PDF 转换选项
    options = {
        'encoding': "UTF-8",
        #'quiet': '', # 临时注释掉 'quiet' 以查看 wkhtmltopdf 的输出/错误
        'javascript-delay': 10000,  # 增加延迟到 10 秒 (根据需要调整)
        'enable-local-file-access': None, # 如果有本地图片等资源，仍需此选项
        'enable-smart-shrinking': None, # 通常有助于布局
        'no-stop-slow-scripts': None, # 允许脚本运行更长时间
        'debug-javascript': None, # 启用 javascript 调试输出 (可能产生大量日志)
        'load-error-handling': 'ignore', # 或 'skip' - 处理资源加载错误
        'load-media-error-handling': 'ignore', # 或 'skip' - 处理媒体加载错误
         # 可以考虑指定页面大小和边距
        'page-size': 'A4',
        'margin-top': '20mm',
        'margin-right': '20mm',
        'margin-bottom': '20mm',
        'margin-left': '20mm',
         # MathJax 渲染的关键选项
        'enable-javascript': None, # 明确启用 JavaScript
        'window-status': 'mathjax-rendering-complete', # 等待这个状态
    }

    # 在 HTML 的 body 末尾添加一个脚本，用于在 MathJax 完成时设置 window.status
    # 注意：这依赖于 MathJax Hub 的信号机制 (MathJax 2)
    js_to_signal_completion = """
    <script type="text/x-mathjax-config">
      MathJax.Hub.Register.StartupHook("End", function() {
        console.log("MathJax rendering finished. Setting window status.");
        window.status = 'mathjax-rendering-complete';
      });
    </script>
    """

    # 将信号脚本添加到 HTML 内容中 (放在 </body> 之前)
    full_html_with_signal = full_html.replace("</body>", js_to_signal_completion + "</body>")

    # 重新写入包含信号脚本的 HTML 文件
    try:
        with open(html_file, 'w', encoding='utf-8') as f:
            f.write(full_html_with_signal)
        # print(f"已更新包含 MathJax 信号脚本的临时 HTML 文件: {html_file}")
    except Exception as e:
        print(f"写入带信号脚本的 HTML 文件失败 {html_file}: {e}")
        # 如果写入失败，仍然尝试使用不带信号的 HTML，但可能效果不好
        options.pop('window-status', None) # 移除 window-status 选项


    # 生成 PDF
    try:
        print(f"正在生成 PDF: {pdf_file} (使用 window-status 等待)")
        # 添加 verbose=True 来获取 pdfkit 的详细输出
        success = pdfkit.from_file(html_file, pdf_file, options=options, configuration=config, verbose=True)
        if success:
            print(f"成功生成 PDF: {pdf_file}")
        else:
            # pdfkit.from_file 在某些情况下即使没有抛出异常也可能返回 False
            print(f"PDF 生成失败 (pdfkit 返回 False): {pdf_file}")

    except Exception as e:
        # 捕获 pdfkit/wkhtmltopdf 可能抛出的异常
        print(f"生成 PDF 时发生错误 {html_file}: {e}")
        # 尝试打印 wkhtmltopdf 的标准错误输出 (如果异常中包含)
        stderr_output = getattr(e, 'stderr', None)
        if stderr_output:
           try:
               print(f"wkhtmltopdf stderr:\n{stderr_output.decode('utf-8', errors='ignore')}")
           except Exception:
               print(f"wkhtmltopdf stderr (无法解码):\n{stderr_output}")
        stdout_output = getattr(e, 'stdout', None)
        if stdout_output:
           try:
               print(f"wkhtmltopdf stdout:\n{stdout_output.decode('utf-8', errors='ignore')}")
           except Exception:
                print(f"wkhtmltopdf stdout (无法解码):\n{stdout_output}")


    # 清理临时 HTML 文件 (可选)
    finally:
        if os.path.exists(html_file):
            try:
                # 在删除前稍微等待，确保 wkhtmltopdf 完全释放了文件句柄
                time.sleep(0.5)
                os.remove(html_file)
                print(f"已删除临时文件: {html_file}")
            except OSError as e:
                print(f"删除临时文件失败 {html_file}: {e}")


def main():
    # 首先设置并检查 wkhtmltopdf 配置
    wkhtml_config = set_pdfkit()
    if not wkhtml_config:
        print("程序因 wkhtmltopdf 配置问题而退出。")
        return # 如果配置失败，则直接退出

    current_dir = os.getcwd()
    print(f"开始处理目录: {current_dir}")

    # 处理当前目录中的文件
    for filename in os.listdir(current_dir):
        if filename.endswith('-md优化-0000.md'): # 简化检查
            # 排除临时 html 文件自身被处理
            if filename.endswith('_temp.html'):
                continue
            md_path = os.path.join(current_dir, filename)
            process_md_file(md_path, wkhtml_config)

    # 处理每个子目录中的文件
    for item in os.listdir(current_dir):
        dir_path = os.path.join(current_dir, item)
        if os.path.isdir(dir_path):
            # 避免处理 .git, venv 等隐藏或特殊目录
            if item.startswith('.') or item == 'venv' or item == '__pycache__' or item == 'mathjax':
                continue
            print(f"进入子目录: {dir_path}")
            try:
                for filename in os.listdir(dir_path):
                     if filename.endswith('-md优化-0000.md'): # 简化检查
                         # 排除临时 html 文件自身被处理
                         if filename.endswith('_temp.html'):
                            continue
                         md_path = os.path.join(dir_path, filename)
                         process_md_file(md_path, wkhtml_config)
            except Exception as e:
                print(f"处理子目录 {dir_path} 时出错: {e}")
            print(f"完成子目录: {dir_path}")

    print("处理完成。")


if __name__ == '__main__':
    main()